{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Build a ChatBot "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have built a simple question-answering pipeline, where we can input a question and get an answer. In addition to single round of question-answering, we can also have a conversation with an LLM by building a chatbot. The chatbot can remember the history of the conversation and respond based on the history. The key to achieve this is to leverage the promt args `chat_history_str` and the data structure `Memory` to manage the conversation history."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import clear_output\n",
    "\n",
    "!pip install -U adalflow[openai,groq,faiss-cpu]\n",
    "clear_output()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import needed modules from Adalflow\n",
    "import os\n",
    "from getpass import getpass\n",
    "from adalflow.core.component import Component\n",
    "from adalflow.core.generator import Generator\n",
    "from adalflow.components.memory.memory import Memory\n",
    "from adalflow.components.model_client import (\n",
    "    OpenAIClient,\n",
    ")  # Here, we use the OpenAIClient as an example, but you can use any other clients (with the corresponding API Key as needed), such as AnthropicAPIClient"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Prompt user to enter their API keys securely\n",
    "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n",
    "# Set environment variables\n",
    "os.environ[\"OPENAI_API_KEY\"] = openai_api_key\n",
    "# Replace with your OpenAI API Key, or you can put it in a .env file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Build the ChatBot pipeline\n",
    "class ChatBot(Component):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.generator = Generator(\n",
    "            model_client=OpenAIClient(), model_kwargs={\"model\": \"gpt-4o-mini\"}\n",
    "        )\n",
    "        self.chat_history = Memory()  # Memory to store the chat history\n",
    "\n",
    "    def call(self) -> str:\n",
    "        print(\"Welcome to the ChatBot. Type anything to chat. Type 'exit' to end.\")\n",
    "        while True:\n",
    "            user_input = input(\"You: \")\n",
    "            if user_input.lower() == \"exit\":\n",
    "                print(\"Goodbye!\")\n",
    "                break\n",
    "            chat_history_str = self.chat_history()\n",
    "            # Generate the response from the user input and chat history\n",
    "            response = self.generator(\n",
    "                prompt_kwargs={\n",
    "                    \"input_str\": user_input,\n",
    "                    \"chat_history_str\": chat_history_str,\n",
    "                },\n",
    "            )\n",
    "            # Save the user input and response to the memory\n",
    "            self.chat_history.add_dialog_turn(\n",
    "                user_query=user_input, assistant_response=response\n",
    "            )\n",
    "            print(f\"ChatBot: {response}\")\n",
    "\n",
    "\n",
    "chatbot = ChatBot()\n",
    "print(chatbot)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chatbot.call()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
